package com.um.springboot.starter.orm.service;


import com.um.springboot.starter.orm.dao.BaseEntityDao;
import com.um.springboot.starter.orm.entity.BaseEntity;
import com.um.springboot.starter.orm.entity.Response;
import com.um.springboot.starter.orm.entity.TreeNode;
import com.um.springboot.starter.utils.NameUtils;
import com.um.springboot.starter.utils.ReflectUtil;
import com.um.springboot.starter.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;


/**
 * @author 邓南辉
 * @date 2020/2/3
 * @copyright 广州优匠科技有限公司
 */
@Slf4j
public class TreeServiceImpl<M extends BaseEntityDao<T>,T extends BaseEntity,N extends TreeNode> extends BaseEntityServiceImpl<M,T> implements TreeService<N,T> {


    protected Class<N> nodeClass = this.currentNodeClass();


    protected Class<N> currentNodeClass() {
        Type superclass = getClass().getGenericSuperclass();
        ParameterizedType type = (ParameterizedType) superclass;
        return (Class<N>) type.getActualTypeArguments()[2];
    }

    /**
     * 查询树结构
     * @param parentId
     * @return
     */
    @Override
    public List<N> getTree(String parentId) {
        List<T> listNode = dao.getList(new String[]{}, new Object[]{}, new String[]{dao.getTableName()+"_parent_id","sort_no"}, new String[]{"asc","asc"});
        List<N> list = toTreeNodeList(listNode,nodeClass);
        N node = listToTreeNode(parentId,list);

        List<N> treeNodes = new ArrayList<>();
        treeNodes.add(node);
        return treeNodes;
    }

    /**
     * 删除单个节点
     * @param id
     * @return
     */
    @Override
    public Boolean deleteNode(String id) {
        List<String> list = new ArrayList<>();
        list.add(id);
        return commonDao.deleteNode(dao.getTableName(),list,dao.getTableName()+"_parent_id");
    }

    /**
     * 批量删除节点
     * @param ids
     * @return
     */
    @Override
    public Boolean deleteNodes(List<String> ids) {
        return commonDao.deleteNode(dao.getTableName(),ids,dao.getTableName()+"_parent_id");
    }

    /**
     * 移动节点
     * @param id
     * @param parentId
     * @return
     */
    @Override
    public Boolean moveNode(String id, String parentId) {
        T entity = dao.getEntity(id);
        if(entity != null){
            ReflectUtil.setValue(entity,NameUtils.getPropertyName(dao.getTableName()) + "ParentId",parentId);
            return dao.update(entity);
        }
        return false;
    }

    /**
     * 列表转成树集合
     * @param parentId
     * @param list
     * @param <N>
     * @return
     */
    protected <N extends TreeNode> N listToTreeNode(String parentId,List<N> list){
        List<TreeNode> nodes = new ArrayList<>();
        N parentNode = null;

        for (N node : list) {
            if (StringUtil.getTrim(node.getParentId()).equals(parentId)) {
                nodes.add(findChildren(node, list));
            }

            if(node.getId().equals(parentId)){
                parentNode = node;
            }
        }
        if(null != parentNode){
            parentNode.setNodes(nodes);
        }
        return parentNode;
    }

    protected <N  extends TreeNode> N findChildren(N tree, List<N> list) {
        for (N node : list) {
            if (StringUtil.getTrim(node.getParentId()).equals(tree.getId())) {

                tree.getNodes().add(findChildren(node, list));
            }
        }
        return tree;
    }



    /**
     * 复制集合
     * @param list
     * @param clazz
     * @param <T>
     * @param <N>
     * @return
     */
    public <T extends BaseEntity, N extends TreeNode> List<N> toTreeNodeList(List<T> list, Class<N> clazz) {
        List<N> array = new ArrayList<>();

        try {
            for (T entity : list) {
                N result = clazz.newInstance();
                /** 拷贝*/
                BeanUtils.copyProperties(entity, result);


                result.setId(StringUtil.getTrim(ReflectUtil.getValue(entity, dao.getPrimaryPropertyName())));
                result.setParentId(StringUtil.getTrim(ReflectUtil.getValue(entity, NameUtils.getPropertyName(dao.getTableName()) + "ParentId")));
                result.setTitle(StringUtil.getTrim(ReflectUtil.getValue(entity, "name")));
                array.add(result);
            }
        }catch (Exception ex){
            log.error("",ex);
        }

        return array;
    }

}
